﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DecTrees
{
    public delegate Boolean Question();
    public delegate void Action();
    public enum AttributeKind { QuestionNode, ActionNode };

    public class Attribute
    {
        string mName;
        Question mQuestion;
        Action mAction;
        AttributeKind mKind;

        /// <summary>
        /// Constructor, build Attribute of question
        /// </summary>
        /// <param name="name">Attribute Name</param>
        /// <param name="AttributeQuestion">Delegate to question function, should return Boolean</param>
        public Attribute(string name, Question AttributeQuestion)
        {
            mName = name;
            mQuestion = AttributeQuestion;
            mKind = AttributeKind.QuestionNode;
        }

        /// <summary>
        /// Constructor, build Attribute of Action
        /// </summary>
        /// <param name="name">Attribute Name</param>
        /// <param name="AttributeAction">Delegate to action function </param>
        public Attribute(string name, Action AttributeAction)
        {
            mName = name;
            mAction = AttributeAction;
            mKind = AttributeKind.ActionNode;
        }

        /// <summary>
        /// Attribute Name Property
        /// </summary>
        public string AttributeName
        {
            get
            {
                return mName;
            }
        }

        /// <summary>
        /// Attribute kind property, could be Action or Question
        /// </summary>
        public AttributeKind Kind
        {
            get
            {
                return mKind;
            }
        }

        /// <summary>
        /// Runs the attribute question delegate and returns its answer.
        /// </summary>
        /// <returns>Boolean</returns>
        public Boolean AttributeQuestion()
        {
            return mQuestion();
        }

        /// <summary>
        /// Runs attribute action delegate
        /// </summary>
        public void AttributeAction()
        {
            mAction();
        }


    }

    public class TreeNode
    {
        private TreeNode leftChild = null;
        private TreeNode rightChild = null;
      
    
        private Attribute mAttribute;


        /// <summary>
        /// Constructor, build Tree node with attribute
        /// </summary>
        /// <param name="attribute">Attribute</param>
        public TreeNode(Attribute attribute)
        {
            mAttribute = attribute;
        }
        
        /// <summary>
        /// Add left child 
        /// </summary>
        /// <param name="treeNode">Left child node</param>
        public void AddLeftTreeNode(TreeNode treeNode)
        {
           
            leftChild = treeNode;
        }

        /// <summary>
        /// Add right child
        /// </summary>
        /// <param name="treeNode">Right child node</param>
        public void AddRightTreeNode(TreeNode treeNode)
        {
            rightChild = treeNode;
        }

        /// <summary>
        /// Is left child exist
        /// </summary>
        /// <returns>Returns True if there is a left child</returns>
        public Boolean IsLeftChild()
        {
            if (leftChild != null)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Is right child exist
        /// </summary>
        /// <returns>Returns true if there is a right child</returns>
        public Boolean IsRightChild()
        {
            if (rightChild != null)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Left child property
        /// </summary>
        public TreeNode LeftChild
        {
            get
            {
                return leftChild;
            }
        }

        /// <summary>
        /// Right child property
        /// </summary>
        public TreeNode RightChild
        {
            get
            {
                return rightChild;
            }
        }
    

        /// <summary>
        /// Attribute property
        /// </summary>
        public Attribute attribute
        {
            get
            {
                return mAttribute;
            }
        }


    }


    public class decitionTree
    {
        private TreeNode root;

        public decitionTree(TreeNode root)
        {
            this.root = root;
        }

        /// <summary>
        /// Scan the tree according to the decitions and activate the action.
        /// </summary>
        public void ScanTree()
        {
            ScanNode(root);
        }

        /// <summary>
        /// Scan each node, if its an action node it activate the action and if it an action node it scans its child 
        /// according to the correct answer.
        /// True : Right child
        /// False: Left child
        /// </summary>
        /// <param name="node">Specific node</param>
        private void ScanNode(TreeNode node)
        {
            if (node.attribute.Kind == AttributeKind.QuestionNode)
            {
                if (node.attribute.AttributeQuestion())
                {
                    if (node.IsRightChild())
                    {
                        ScanNode(node.RightChild);
                    }
                }
                else
                {
                    if (node.IsLeftChild())
                    {
                        ScanNode(node.LeftChild);
                    }
                }
            }
            //this case node.attribute.Kind == AttributeKind.ActionNode - run Nodes action.
            else
            {
                node.attribute.AttributeAction();
            }


        }
    }

}
